#ifndef SOCK_H_
#define SOCK_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sendfile.h>

#define HANDLE_ERROR_EXIT(error_string) do{perror(error_string);exit(-1);}while(0)

/*server*/
void create_bind_listen(int *listen_fd, int port, int backlog){

	*listen_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == *listen_fd){
		HANDLE_ERROR_EXIT("can not create sock");
	}

	struct sockaddr_in server_addr;
	memset(&server_addr, 0, sizeof(server_addr));

	server_addr.sin_port = htons(port);
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

	int ret;
	ret = bind(*listen_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
	if(-1 == ret){
		HANDLE_ERROR_EXIT("can not bind");
	}
	ret = listen(*listen_fd, backlog);
	if(-1 == ret){
		HANDLE_ERROR_EXIT("can not listen");
	}
}

/*client*/
void create_and_conn(int *sock_fd, char *ip, int port){
	*sock_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == *sock_fd){
		HANDLE_ERROR_EXIT("can not create sock");
	}
	struct sockaddr_in server_addr;
	memset(&server_addr, 0, sizeof(server_addr));

	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	server_addr.sin_addr.s_addr = inet_addr(ip);

	int ret;
	ret = connect(*sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
	if(-1 == ret){
		HANDLE_ERROR_EXIT("can not bind");
	}
}

/*send file*/
void SendFile(char *path, int conn_fd){
	struct stat s;
	int filefd = open(path, O_RDONLY);
	sendfile(conn_fd, filefd, NULL, s.st_size);
	close(filefd);
}
/*send dir*/
void SendDir(char *path, int conn_fd){
	struct dirent *temp_path;
	struct stat s;
	DIR *dir;
	char newpath[512];

	dir = opendir(path);
	if(dir == NULL){
		perror("opendir error");
		return;
	}
	while((temp_path = readdir(dir))!=NULL){
		
		if(!strcmp(temp_path->d_name,".")||!strcmp(temp_path->d_name,".."))
			continue;
		sprintf(newpath, "%s/%s", path, temp_path->d_name);
		
		lstat(newpath, &s);
		if(S_ISDIR(s.st_mode)){
			SendDir(newpath, conn_fd);
		}else if(S_ISREG(s.st_mode)){
			int filefd = open(newpath, O_RDONLY);
			sendfile(conn_fd, filefd, NULL, s.st_size);
			close(filefd);
		}
	}
	closedir(dir);
}
/*send file or dir*/
void Send(char *path, int conn_fd){
	struct stat s;
	lstat(path, &s);
	if(S_ISREG(s.st_mode)){
		SendFile(path, conn_fd);
	}else if(S_ISDIR(s.st_mode)){
		SendDir(path, conn_fd);
	}
}

#endif
